package models

import (
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/models/qpay"
	"gitchina/kly_service/util"
	"math"
	"time"
)

var mockPayID ID

type GatewayPayMock struct {
	GatewayPay
}

func init() {
	mockPayID.Encode(1, 1, 1, time.Now().UnixNano())
}

func (gp *GatewayPayMock) PreTopUp(memberId int, amount float32) (ID, error) {
	return gp.GatewayPay.PreTopUp(memberId, amount)
}

func (gp *GatewayPayMock) PostTopUp(p data.PaymentDto, i PostPayItem) error {
	return gp.GatewayPay.PostTopUp(p, i)
}

func (gp *GatewayPayMock) PrePayDeposit(item PayItem) (ID, error) {
	return gp.prePay(item)
}

func (gp *GatewayPayMock) DoPayDeposit(payID ID) (interface{}, error) {
	return gp.doPay(payID, 0)
}

func (gp *GatewayPayMock) PostPayDeposit(p data.PaymentDto, i PostPayItem) error {
	return gp.GatewayPay.PostPayDeposit(p, i)
}

func (gp *GatewayPayMock) PrePayWaybill(item PayItem) (ID, error) {
	return gp.prePay(item)
}

func (gp *GatewayPayMock) DoPayWaybill(payID ID) (interface{}, error) {
	return gp.doPay(payID, 1)
}

func (gp *GatewayPayMock) PostPayWaybill(p data.PaymentDto, i PostPayItem) error {
	return gp.GatewayPay.PostPayWaybill(p, i)
}

func (gp *GatewayPayMock) prePay(item PayItem) (paymentId ID, err error) {
	return gp.GatewayPay.prePay(item)
}

func (gp *GatewayPayMock) doPay(payID ID, payFor int) (*QPayRS, error) {
	var prepo data.PayRepo
	var applyResult *qpay.PaymentResult
	var resendResult *qpay.ResultV2
	var paySubject string

	if payFor == 0 {
		paySubject = "支付订金"
	} else {
		paySubject = "支付运单"
	}

	rs := new(QPayRS)

	_, _, _, pid, err := payID.Decode()
	if err != nil {
		return nil, errors.New(errors.MSG_Pay_Invalid_ID)
	}

	pd, err := prepo.GetPaymentDetailByPayID(int(pid))
	if err != nil {
		return nil, errors.New(errors.MSG_Pay_Error)
	}

	c, err := prepo.GetQPayBankCard(pd.MemberId, pd.CardId)
	if err != nil {
		return nil, errors.New(errors.MSG_Pay_Error)
	}

	ok, q := prepo.GetQPay(int(pid))
	if !ok {
		q = &data.QPayDto{
			ID:       int(pid),
			MemberID: pd.MemberId,
			State:    0,
			Amount:   int(math.Round(float64(pd.DepositAmount * 100))),
		}

		err = prepo.AddQPay(q)
		if err == nil {
			p := qpay.NewPayment()
			p.Subject = paySubject
			p.Amount = fmt.Sprintf("%d", q.Amount)
			p.AgreeID = c.PartnerID
			p.OrderID = string(mockPayID)
			applyResult, err = p.Apply()
			if applyResult.OK() {
				err = prepo.SetQPayApplyOK(q.ID, applyResult.Thpinfo(), applyResult.Undecoded())
				if err == nil {
					rs.State = 1
				}
			} else {
				prepo.UpdateQPayUndecoded(q.ID, applyResult.Undecoded())
			}
		}
	} else {
		p := qpay.NewPayment()
		p.AgreeID = c.PartnerID
		p.OrderID = string(mockPayID)
		p.Thpinfo = q.Params
		resendResult, err = p.Resend()
		if resendResult.OK() {
			rs.State = 1
			prepo.UpdateQPayUndecoded(q.ID, resendResult.Undecoded())
		}
	}

	rs.PayID = string(payID)
	if err != nil {
		util.GetLogger().Error("[pg.doPay] - error:%s", err.Error())
		err = errors.New(errors.MSG_Pay_Error)
	}

	return rs, err
}

func (gp *GatewayPayMock) Confirm(memberID, payID ID, params string) error {
	var prepo = new(data.PayRepo)

	_, _, _, mid, err := memberID.Decode()
	if err != nil {
		return errors.New(errors.MSG_Mbr_Invalid)
	}

	_, _, _, pid, err := payID.Decode()
	if err != nil {
		return errors.New(errors.MSG_Pay_Invalid_ID)
	}

	ok, info := prepo.GetQPay(int(pid))
	if ok {
		if info.MemberID != int(mid) {
			return errors.New(errors.MSG_Pay_Not_Same_Payer)
		}
		if info.State != 1 {
			return errors.New(errors.MSG_Pay_Error)
		}
	} else {
		return errors.New(errors.MSG_Pay_Error)
	}

	pd, err := prepo.GetPaymentDetailByPayID(int(pid))
	if err != nil {
		util.GetLogger().Error("[PayConfirm] - error:%s", err.Error())
		return errors.New(errors.MSG_Pay_Error)
	}

	card, err := prepo.GetQPayBankCard(int(mid), pd.CardId)
	if err != nil {
		util.GetLogger().Error("[PayConfirm] - error:%s", err.Error())
		return errors.New(errors.MSG_Pay_Error)
	}

	p := qpay.NewPayment()
	p.OrderID = string(mockPayID)
	p.AgreeID = card.PartnerID
	p.Thpinfo = info.Params
	result, err := p.Confirm(params)
	if err != nil {
		util.GetLogger().Error("[PayConfirm] - error:%s", err.Error())
		return errors.New(errors.MSG_Pay_Error)
	}
	if result.OK() {
		prepo.SetQPayConfirmOK(int(pid), result.Undecoded())
	} else {
		prepo.UpdateQPayUndecoded(int(pid), result.Undecoded())
	}

	return nil
}

func ChangeMockPayID() {
	mockPayID.Encode(1, 1, 1, time.Now().UnixNano())
}
